package com.geek.bulk.interceptor;

import com.geek.bulk.echo.CircuitBreakerProperties;
import com.geek.bulk.echo.CustomCircuitBreaker;
import org.apache.commons.lang3.concurrent.CircuitBreakingException;
import org.eclipse.microprofile.faulttolerance.exceptions.CircuitBreakerOpenException;
import org.eclipse.microprofile.faulttolerance.CircuitBreaker;

import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.ConcurrentHashMap;


/**
 * 电路熔断器(Circuit Breaker)
 */
@Interceptor
public class CircuitBreakerInterceptor extends AnnotatedInterceptor<CircuitBreaker> {


    private ConcurrentHashMap<CircuitBreaker, CustomCircuitBreaker> concurrentHashMap = new ConcurrentHashMap();
    /**
     * 断路器拦截器 实现
     * @param context
     * @param circuitBreaker
     * @return
     * @throws Exception
     */
    @Override
    protected Object execute(InvocationContext context, CircuitBreaker circuitBreaker) throws Exception {
        CustomCircuitBreaker breaker = concurrentHashMap.computeIfAbsent(circuitBreaker, key -> new CustomCircuitBreaker.Default(CircuitBreakerProperties.build(circuitBreaker)));

        if (!breaker.allowRequest()) {
            throw new CircuitBreakerOpenException();
        }
        Object proceed = null;
        try {
            proceed = context.proceed();
            breaker.markSuccess();
        } catch (Exception e) {
            //todo debug时; RnntimeException需要.getCause多次才可以得到
            Throwable failure = e instanceof InvocationTargetException ? e.getCause() : e;
            breaker.failure(failure);
            throw new CircuitBreakingException(e);
        }
        return proceed;
    }


}
